package demoMod.gdxform.ui;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import demoMod.gdxform.core.AbstractAction;
import demoMod.gdxform.core.FormManager;
import demoMod.gdxform.helpers.FontHelper;
import demoMod.gdxform.interfaces.ResizeEventSubscriber;

public class GCheckBox extends GLabel implements ResizeEventSubscriber {
    private Texture bgTexture;
    private Texture fgTexture;

    private Texture unselectedTexture;
    private Texture selectedTexture;
    private Texture partialSelectedTexture;
    private Texture disabledTexture;
    private Color disabledColor = Color.GRAY.cpy();

    protected boolean clicked = false;

    protected int state = 0;

    public GCheckBox(float x, float y, float width, float height, BitmapFont font) {
        this(x, y, width, height);
        setFont(font);
    }

    public GCheckBox(float x, float y, float width, float height) {
        super(x, y, width, height);
        setBgTexture(initBgTexture(new Pixmap((int)width, (int)height, Pixmap.Format.RGBA8888)));
        setUnselectedTexture(initUnselectedTexture(new Pixmap((int)width, (int)height, Pixmap.Format.RGBA8888)));
        setSelectedTexture(initSelectedTexture(new Pixmap((int)width, (int)height, Pixmap.Format.RGBA8888)));
        setPartialSelectedTexture(initPartialSelectedTexture(new Pixmap((int)width, (int)height, Pixmap.Format.RGBA8888)));
        setDisabledTexture(initDisabledTexture(new Pixmap((int)width, (int)height, Pixmap.Format.RGBA8888)));
    }

    protected Texture initBgTexture(Pixmap pixmap) {
        pixmap.setColor(Color.WHITE);
        pixmap.fill();
        return new Texture(pixmap);
    }

    protected Texture initUnselectedTexture(Pixmap pixmap) {
        return new Texture(pixmap);
    }

    protected Texture initSelectedTexture(Pixmap pixmap) {
        pixmap.setColor(Color.GREEN);
        int pos = (int) (getWidth() * 0.2F);
        int wid = pos * 3;
        pixmap.fillRectangle(pos, pos, wid, wid);
        return new Texture(pixmap);
    }

    protected Texture initPartialSelectedTexture(Pixmap pixmap) {
        pixmap.setColor(Color.YELLOW);
        int pos = (int) (getWidth() * 0.2F);
        int wid = pos * 3;
        pixmap.fillRectangle(pos, pos, wid, wid);
        return new Texture(pixmap);
    }

    protected Texture initDisabledTexture(Pixmap pixmap) {
        pixmap.setColor(Color.GRAY);
        int pos = (int) (getWidth() * 0.2F);
        int wid = pos * 3;
        pixmap.fillRectangle(pos, pos, wid, wid);
        return new Texture(pixmap);
    }

    @Override
    public void render(SpriteBatch sb) {
        if (!this.visible()) return;
        sb.setColor(Color.WHITE);
        if (this.bgTexture != null) {
            sb.draw(this.bgTexture, getX(true), getY(true), getWidth(), getHeight());
        }
        if (this.fgTexture != null) {
            if (enabled()) {
                sb.draw(this.fgTexture, getX(true), getY(true), getWidth(), getHeight());
            } else if (this.disabledTexture != null) {
                sb.draw(this.disabledTexture, getX(true), getY(true), getWidth(), getHeight());
            }
        }
        if (this.getFont() == null) return;
        FontHelper.renderSmartText(sb, this.getFont(), this.getText(), this.getX(true) + getWidth(), this.getY(true) + this.getFont().getLineHeight(), Integer.MAX_VALUE, this.getFont().getLineHeight(), enabled() ? this.getColor() : this.disabledColor);
    }

    public void setBgTexture(Texture bgTexture) {
        if (this.bgTexture != null) {
            this.bgTexture.dispose();
        }
        this.bgTexture = bgTexture;
    }

    private void setFgTexture(Texture fgTexture) {
        this.fgTexture = fgTexture;
    }

    public void setUnselectedTexture(Texture unselectedTexture) {
        if (this.unselectedTexture != null) {
            this.unselectedTexture.dispose();
        }
        this.unselectedTexture = unselectedTexture;
    }

    public void setSelectedTexture(Texture selectedTexture) {
        if (this.selectedTexture != null) {
            this.selectedTexture.dispose();
        }
        this.selectedTexture = selectedTexture;
    }

    public void setPartialSelectedTexture(Texture partialSelectedTexture) {
        if (this.partialSelectedTexture != null) {
            this.partialSelectedTexture.dispose();
        }
        this.partialSelectedTexture = partialSelectedTexture;
    }

    public void setDisabledTexture(Texture disabledTexture) {
        if (this.disabledTexture != null) {
            this.disabledTexture.dispose();
        }
        this.disabledTexture = disabledTexture;
    }

    public void setDisabledColor(Color disabledColor) {
        this.disabledColor = disabledColor;
    }

    @Override
    public void resize(float deltaX, float deltaY, boolean fromParent) {

    }

    @Override
    public boolean clickDown(int screenX, int screenY, int button) {
        if (!this.visible()) return false;
        clicked = screenX >= getX(true) && screenX <= getX(true) + getWidth() &&
                Gdx.graphics.getHeight() - screenY >= getY(true) && Gdx.graphics.getHeight() - screenY <= getY(true) + getHeight();
        if (clicked && enabled()) {
            FormManager.getInstance().getEventHooks().setCurrentFocusedElement(this);
        }
        return clicked;
    }

    @Override
    public boolean clickUp(int screenX, int screenY, int button) {
        if (!this.visible()) return false;
        if (clicked && enabled()) {
            clicked = false;
            if (screenX >= getX(true) && screenX <= getX(true) + getWidth() &&
                    Gdx.graphics.getHeight() - screenY >= getY(true) && Gdx.graphics.getHeight() - screenY <= getY(true) + getHeight()) {
                changeState(2);
                onClick();
            }
            return true;
        }
        return false;
    }

    public void setState(int state) {
        this.state = state - 1;
        changeState(3);
    }

    public int getState() {
        return state;
    }

    protected void changeState(int stateUpperLimit) {
        int stateBefore = state;
        state++;
        state %= stateUpperLimit;
        actionManager.addToSequenceBot(getStateChangeAction(stateBefore));
        actionManager.addToSequenceBot(new AbstractAction.Builder().setActionBody(duration -> {
            switch (state) {
                case 0:
                    setFgTexture(this.unselectedTexture);
                    break;
                case 1:
                    setFgTexture(this.selectedTexture);
                    break;
                case 2:
                    setFgTexture(this.partialSelectedTexture);
                    break;
                default:
                    throw new IllegalStateException("Illegal state: " + this.state);
            }
            return true;
        }).build());
    }

    protected AbstractAction getStateChangeAction(int stateBefore) {
        return new AbstractAction.Builder().setActionBody(duration -> true).build();
    }

    public void onClick() {

    }

    @Override
    public void dispose() {
        super.dispose();
        if (this.bgTexture != null) {
            this.bgTexture.dispose();
        }
        if (this.fgTexture != null) {
            this.fgTexture.dispose();
        }
    }

    @Override
    public boolean hasFocus() {
        return true;
    }
}
